gusucode.com > VC++ RingSDK界面库 > VC++ RingSDK界面库/code/libsrc/ringdows/ringoptionview.cpp

    /**********************************************************************
//
//
//        ##########                          ######  #########   # ######    #
//      #############                      ########### ######### #########  ###
//     ######## # ###  ##                 ############# ##    ## #####  # ####
//     ####  ##    ## ###                 ###     ### # #      #####   #####
//          #     ###  #            #     ##       ##  ##      ##     ###
//         ## ###### ##      ##  ####    ####          #       #     ##
//       #########  ###  ## ### #######   ######      ##      ##    ###
//      ######      ##  ######  ##  ##       ####     #      ##     ####
//     #######     ##   ###### ##  ###          ##   ##     ###    ######
//     #########   ##  ###### ## ######         ### ##    ###      #  #####
//    ##    ###### ####### ### #### ##  ## #######  ########      ##    ####
//    ##      #### ###  #  ### ### ##  ##########   ######       ##      ####
//   ##         ##                ##   #########    ####         #         ##
//               #              ###
//                              ##
//                             ###
//                             ##
//
//
//							临风程序界面类库 ringdows.lib
//作者:临风
//
//版本:1.0
//
//声明:本类库可以自由使用而不须对作者作出任何回报,但作者希望能得到
//		  你的鼓励和支持。你可以对类库源码作出修改和改进,但希望你能在
//		  修改的同时给作者一份同样的副本。
//		  本类库不得用于任何商业用途,如确实需要,请与作者联系。
//
//e-mail:ringphone@sina.com
//
//原文件名:ringoptionview.cpp
//
//说明:类似DELPHI属性控件控制
//
**********************************************************************/
#define MAKE_SELF_LIB
//#include "ringdebug.h"
#include "ringdows.h"

RingOptionView::RingOptionView()
{
	m_edit = NULL;
	m_combo = m_comboSel = NULL;
	m_button = NULL;
	m_pen = NULL;
	m_SplitPos = 0;
	m_LeftPos = 0;
	m_cursorSize = LoadCursor(NULL,IDC_SIZEWE);
	m_cursor = LoadCursor(NULL,IDC_ARROW);
	m_bCapture = FALSE;
	m_bUpdate = FALSE;
}

RingOptionView::~RingOptionView()
{
	if(m_pen)
		DeleteObject(m_pen);
}

BOOL RingOptionView::Create(DWORD dwStyle,DWORD dwExStyle,LPCTSTR szInitText,UINT uId,int x,int y,int width,int height)
{
	dwStyle |= (LBS_HASSTRINGS|LBS_OWNERDRAWFIXED|LBS_NOTIFY|WS_VSCROLL);
	
	if(RingControls::Create(dwStyle,dwExStyle,szInitText,uId,x,y,width,height))
	{
		RingControls::SetOwnerDraw(FALSE,(UINT)0xFFFFFFFF);
		OnCreate(m_hWnd);
		return TRUE;
	}
	return FALSE;
}
	
BOOL RingOptionView::Create(UINT uId,int x/*=0*/,int y/*=0*/,int width/*=-999*/,int height/*=-999*/)
{
	DWORD dwExStyle = 0;
	if(width == -999 || height == -999)
		dwExStyle = RTV_FITPARENTSIZE;
	
	return Create(LBS_HASSTRINGS|LBS_OWNERDRAWFIXED|LBS_NOTIFY|WS_VSCROLL,
						dwExStyle,"",uId,x,y,width,height);
}

void RingOptionView::OnCreate(HWND)
{
	RECT rc;
	GetClientRect(&rc);
	m_SplitPos = (rc.right - rc.left) / 2;

	if(m_pen == NULL)
		m_pen = CreatePen(PS_SOLID,1,0x00C6C6C6);
	SetItemHeight(GetItemHeight() + 2);
//StartDebug(m_hWnd);
}

BOOL RingOptionView::Attach(HWND hWnd)
{
	//因为ListBox一旦创建其Style就不可改变,因此这里检测其Style
	//如果不是自绘则需要先Destroy然后再Create	
	DWORD style = GetWindowLong(hWnd,GWL_STYLE);
	style &= ~(LBS_SORT|LBS_MULTIPLESEL|LBS_MULTICOLUMN);
	DWORD st = LBS_HASSTRINGS|LBS_OWNERDRAWFIXED|LBS_NOTIFY;
	if((style & st) != st)
	{
		RECT rc;
		HWND hwnd;
		
		style |=	(st|WS_VSCROLL);
		
		DWORD exstyle = GetWindowLong(hWnd,GWL_EXSTYLE);
		
		GetWindowRect(hWnd,&rc);
		hwnd = ::GetParent(hWnd);
		
		ScreenToClient(hwnd,(LPPOINT)&rc);
		ScreenToClient(hwnd,(LPPOINT)&rc+1);
		
		m_ID = GetWindowLong(hWnd,GWL_ID);
		
		DestroyWindow(hWnd);
		
		if(RingControls::Create(style,exstyle,"",m_ID,
			rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top))
		{
			RingControls::SetOwnerDraw(FALSE,(UINT)0xFFFFFFFF);
			OnFitSize(m_parent->Handle(),0,0);
			OnCreate(m_hWnd);
			return TRUE;
		}
	}
	else
		if(RingBaseWnd::Attach(hWnd))
		{
			RingControls::SetOwnerDraw(FALSE,(UINT)0xFFFFFFFF);
			OnFitSize(m_parent->Handle(),0,0);
			OnCreate(m_hWnd);
			return TRUE;
		}
		
	return FALSE;
}

BOOL RingOptionView::OnFitSize(HWND hWnd,WPARAM wParam,LPARAM lParam)
{
	BOOL bOK = RingControls::OnFitSize(hWnd,wParam,lParam);
	RECT rc;
	GetClientRect(&rc);
	m_SplitPos = (rc.right - rc.left + m_LeftPos) / 2;
	return bOK;
}

BOOL RingOptionView::OnDrawItem(LPDRAWITEMSTRUCT lpds)
{
	if(lpds->itemAction & ODA_FOCUS)
		return TRUE;

	RECT rc;
	int cx = ClientWidth() - 1;
	CopyRect(&rc,&lpds->rcItem);
	rc.right = m_SplitPos;
	
	int ndc = SaveDC(lpds->hDC);

	HGLOBAL m_old = SelectObject(lpds->hDC,m_pen);
	SelectObject(lpds->hDC,m_brush);
	
	RingOptionItem* item = (RingOptionItem*)lpds->itemData;
	
	if((lpds->itemState & ODS_SELECTED))
	{		
		::SetBkColor(lpds->hDC,GetSysColor(COLOR_HIGHLIGHT));
		::SetTextColor(lpds->hDC,GetSysColor(COLOR_HIGHLIGHTTEXT));
		if(item->IsPackItem() || item->IsSubItem())
		{
			rc.left += m_LeftPos;
			ExtTextOut(lpds->hDC,0,0,ETO_OPAQUE,&rc,NULL,0,NULL);
			rc.left -= m_LeftPos;
		}
		else
			ExtTextOut(lpds->hDC,0,0,ETO_OPAQUE,&rc,NULL,0,NULL);
		DrawEdge(lpds->hDC,&lpds->rcItem,EDGE_SUNKEN,BF_RECT);

		if(item && !m_bUpdate)
			item->EnterEdit(rc.right,rc.top,cx-rc.right,rc.bottom-rc.top);
		m_bUpdate = FALSE;
	}
	else
	{
		if(item && item->GetCtrl())
			item->ExitEdit();
		FillRect(lpds->hDC,&lpds->rcItem,m_brush);		
	}

	rc.left += m_LeftPos;
	MoveToEx(lpds->hDC,rc.left,rc.top,NULL);
	LineTo(lpds->hDC,rc.right,rc.top);
	LineTo(lpds->hDC,rc.right,rc.bottom);
	LineTo(lpds->hDC,rc.left,rc.bottom);
	if(!(lpds->itemState & ODS_SELECTED))
		LineTo(lpds->hDC,rc.left,rc.top);
	MoveToEx(lpds->hDC,rc.right,rc.top,NULL);
	LineTo(lpds->hDC,cx,rc.top);
	LineTo(lpds->hDC,cx,rc.bottom);
	LineTo(lpds->hDC,rc.right,rc.bottom);
	LineTo(lpds->hDC,rc.right,rc.top);
	
	InflateRect(&rc,-1,-2);
	OffsetRect(&rc,1,2);
	
	if(item)
	{
		HFONT hfont = NULL;
		if(item->IsSubItem())
			hfont = (HFONT)SelectObject(lpds->hDC,m_fontSubItem.GetFont());
		else if(item->IsPackItem())
			hfont = (HFONT)SelectObject(lpds->hDC,m_fontPack.GetFont());

		DrawText(lpds->hDC,item->GetName(),strlen(item->GetName()),&rc,DT_LEFT|DT_END_ELLIPSIS);		
		rc.left = rc.right + 2;
		rc.right = cx;
		
		if(hfont)
			SelectObject(lpds->hDC,hfont);

		item->DrawValue(lpds->hDC,&rc);		
	}
	RestoreDC(lpds->hDC,ndc);

	return TRUE;
}

//////////////////////////////////////////////////////////
//
//编辑控件值改变(列表选择变动,点击按钮,编辑框失去焦点),
//执行绑定的相应处理函数,如果未绑定函数,发送相应通知消息.
//
//////////////////////////////////////////////////////////
void RingOptionView::SendNotify(int type)
{
	RingOptionItem* item = GetOptionItem();
	if(item && !item->OnBeforeNotify(type))
	{
		ROPVNOTIFY opnm;
		opnm.hdr.code = type;
		opnm.hdr.hwndFrom = m_hWnd;
		opnm.hdr.idFrom = m_ID;
		opnm.item = item;
		opnm.lpszName = item->GetName();
		opnm.lpszText = item->GetText();
		opnm.lpszOrgText = item->GetPrevText();
		opnm.lData = item->GetData();
		opnm.lValue = item->GetInt();
		opnm.uType = item->GetType();
		SendMessage(m_parent->Handle(),WM_NOTIFY,GetCurSel(),(LPARAM)&opnm);
	}
}

LRESULT RingOptionView::RingdowProc(HWND hWnd,RINGPARAMS param)
{
	switch(param.uMsg)
	{
		case LB_ADDFILE:
		case LB_DIR:
			//取消列表文件功能,不支持
			return LB_ERR;
		case WM_DRAWITEM:
			//BUTTON必须自绘
			NotifyChild(m_hWnd,param.uMsg,param.wParam,param.lParam);
			break;
		case WM_COMMAND:			
			if(param.shortval.high == CBN_SELCHANGE && 
				((m_combo && param.shortval.low == LOWORD(m_combo)) ||
				 (m_comboSel && param.shortval.low == LOWORD(m_comboSel))))
				SendNotify(ROPVN_SELCHANGE);
			else if(m_button && param.shortval.low == LOWORD(m_button)
				&& param.shortval.high == BN_CLICKED)
				SendNotify(ROPVN_BUTTONCLICK);
			else if(m_edit && m_button == NULL && param.shortval.low == LOWORD(m_edit)
				&& param.shortval.high == EN_KILLFOCUS)
				SendNotify(ROPVN_VALUECHANGE);
			break;
		case WM_MOUSEMOVE:
			if(m_bCapture)
			{
				if(param.mousept.x > m_LeftPos + 16 && 
					param.mousept.x < ClientWidth() - 32)
				{
					if(m_SplitPos != param.mousept.x)
					{
						m_SplitPos = param.mousept.x;
						InvalidateRect(m_hWnd,NULL,TRUE);
					}					
				}
				return 0;
			}
			else if(param.mousept.y < GetCount() * GetItemHeight() && 
						param.mousept.x > m_SplitPos-3 &&
						param.mousept.x < m_SplitPos+3)
				SetCursor(m_cursorSize);
			else
				SetCursor(m_cursor);
			//不支持多选。注意该段代码拿掉会导致数据包因展开需调整
			//topitem而使高亮选择变动到subitem.
			if((param.wParam & MK_LBUTTON) == MK_LBUTTON && !m_bCapture)
				return 0;
			break;
		case WM_LBUTTONDOWN:
			if(param.mousept.y < GetCount() * GetItemHeight() && 
				param.mousept.x > m_SplitPos-3 &&
				param.mousept.x < m_SplitPos+3)
			{
				SetCursor(m_cursorSize);
				m_bCapture = TRUE;
				SetCapture(m_hWnd);
				return 0;
			}
			else
			{
				RingOptionItem* item = GetOptionItem(GetCurSel());
				m_bUpdate = TRUE;
				if(item && item->GetCtrl() && !item->IsEditVisible())
				{
					//原选中项退出编辑,item->ExitEdit()会通知item值改变
					item->ExitEdit();					
				}
				
				LRESULT res = RingControls::RingdowProc(hWnd,param);
				
				item = GetOptionItem(GetCurSel());
				
				if(item)
				{
					RECT rc;
					if(GetItemRect(GetCurSel(),&rc))
					{
						rc.left = m_SplitPos;
						item->EnterEdit(rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top);
					}
					if(param.mousept.x < m_LeftPos && item->IsPackItem())
						((RingOptionItemPack*)item)->AutoExpand();					
				}
				return res;				
			}			
		case WM_LBUTTONUP:
			if(m_bCapture)
				ReleaseCapture();
			m_bCapture = FALSE;
			break;
		case WM_VSCROLL:
		case (WM_MOUSELAST+1)://=WM_MOUSEWHEEL
		{
			LRESULT res = RingControls::RingdowProc(hWnd,param);
			if(param.uMsg == (WM_MOUSELAST+1) || 
				(param.uMsg == WM_VSCROLL && param.wParam == SB_ENDSCROLL))
				InvalidateRect(m_hWnd,NULL,TRUE);
			return res;
		}
		case LB_ADDSTRING:
		case LB_INSERTSTRING:
		{
			int type = 0;
			LPARAM lParam = param.lParam;
			RingOptionItem* item;
			LRESULT res = LB_ERR;

			if(param.wParam != -1)
			{
				//LB_INSERTSTRING并加到最后param.wParam为-1
				type = param.shortval.high;
				param.shortval.high = 0;
				if(MASK_MATCH(type,OPTYPE_EXTERN))//外部数据
				{
					try
					{
						param.lParam = (LPARAM)(((RingOptionItem*)lParam)->GetName());
					}
					catch (...)
					{
						return LB_ERR;
					}
				}
			}
			item = OnAddString(type,(LPCTSTR)lParam);
			if(item)
			{
				res = RingControls::RingdowProc(hWnd,param);
				if(res != LB_ERR && res != LB_ERRSPACE)
				{
					item->SetParent(this);
					SendMessage(m_hWnd,LB_SETITEMDATA,res,(LPARAM)item);
				}
				else
					if((type & OPTYPE_EXTERN) != OPTYPE_EXTERN)//外部数据
						delete item;
			}
			return res;
		}
		case LB_DELETESTRING:
		{			
			OnDelString(param.wParam,param.lParam==DELITEM_HIDE?DELITEM_HIDE:0);
			break;
		}
		case LB_RESETCONTENT:
		{
			int n = GetCount();
			for(int i=0;i<n;i++)
				OnDelString(i,DELITEM_CLEAR);
			break;
		}
		case LB_SETITEMDATA:
		{	
			LONG item = CallWindowProc(m_DefProc,m_hWnd,LB_GETITEMDATA,param.wParam,0);
			if(item != LB_ERR)
				if(item == 0)
					break;
				else
				{
					try
					{
						((RingOptionItem*)item)->SetData(param.lParam);
						return TRUE;
					}
					catch(...)
					{						
					}
				}
			return LB_ERR;
		}
		case LB_GETITEMDATA:
		{	
			LONG item = RingControls::RingdowProc(hWnd,param);
			if(item != LB_ERR)
			{
				if(item == 0)
					return 0;
				else
				{
					try
					{
						return ((RingOptionItem*)item)->GetData();
					}
					catch(...)
					{
					}
				}
			}
			return LB_ERR;
		}
		//case WM_ERASEBKGND:
		//case WM_WINDOWPOSCHANGED:
		//	return 0;
	}
	return RingControls::RingdowProc(hWnd,param);
}

RingOptionItem* RingOptionView::GetOptionItem(int index/*=INDEX_CURSEL*/)
{
	if(index == INDEX_CURSEL)
		index = GetCurSel();

	LONG item = CallWindowProc(m_DefProc,m_hWnd,LB_GETITEMDATA,index,0);
	if(item == LB_ERR)
		item = 0;
	return (RingOptionItem*)item;
}

RingOptionItem* RingOptionView::GetOptionItem(LPCTSTR lpName)
{
	int index = FindMatchString(lpName);
	if(index != LB_ERR)
		return GetOptionItem(index);
	else
		return NULL;
}

RingOptionItemPack* RingOptionView::GetPackItem(LPCTSTR lpName)
{
	int idx,index = FindMatchString(lpName);
	if(index != LB_ERR)
	{
		RingOptionItem* item = GetOptionItem(index);

		while(item)
		{
			//只有是PACK才返回
			if(item->GetType() == OPTYPE_PACK)
				return (RingOptionItemPack*)item;

			idx = FindMatchString(lpName,index);
			//未找到或已找了一圈
			if(idx == LB_ERR || idx <= index)
				return NULL;
			index = idx;
			item = GetOptionItem(index);
		}
	}
	return NULL;
}

RingOptionItemPack* RingOptionView::GetPackItem(int index)
{
	if(index != LB_ERR)
	{
		RingOptionItem* item = GetOptionItem(index);
		
		//只有是PACK才返回
		if(item->GetType() == OPTYPE_PACK)
			return (RingOptionItemPack*)item;
	}
	return NULL;
}

//重载GetInt为获得属性值,GetText无法重载,改变其行为需
//重载GetItemText
int RingOptionView::GetInt(int index/*=INDEX_CURSEL*/)
{
	if(index == INDEX_CURSEL)
		index = GetCurSel();

	RingOptionItem* item = GetOptionItem(index);
	if(item)
		return item->GetInt();
	else
		return 0;
}

int RingOptionView::GetInt(LPCTSTR lpName)
{
	int index = FindMatchString(lpName);

	if(index == LB_ERR)
		return 0;
	else
		return GetInt(index);
}

//获取选项DATA
int RingOptionView::GetSelectData(int index)
{
	if(index == INDEX_CURSEL)
		index = GetCurSel();
	
	RingOptionItem* item = GetOptionItem(index);
	if(item && MASK_MATCH(item->GetType(),OPTYPE_LIST))
		return ((RingOptionItemList*)item)->GetItemData(index);
	else
		return 0;
}

int RingOptionView::GetSelectData(LPCTSTR lpName)
{
	int index = FindMatchString(lpName);
	
	if(index == LB_ERR)
		return 0;
	else
		return GetSelectData(index);
}

//获取属性名称(原GetText的行为)
LPCTSTR RingOptionView::GetName(int index)
{
	RingOptionItem* item = GetOptionItem(index);
	if(item)
		return item->GetName();
	else
		return NULL;
}

int RingOptionView::GetType(int nIndex)
{
	RingOptionItem* item = GetOptionItem(nIndex);
	if(item)
		return item->GetType();
	else
		return OPTYPE_NONE;
}

//重载该函数使GetText返回属性值,真正的Item Text
//用GetName得到
int RingOptionView::GetItemText(int index,LPTSTR lpBuf,int size)
{
	if(index == INDEX_CURSEL)
		index = GetCurSel();

	RingOptionItem* item = GetOptionItem(index);
	if(item)
	{
		LPCTSTR lps = item->GetText();
		lstrcpyn(lpBuf,lps,size);
		return lstrlen(lpBuf);
	}
	return 0;
}

int RingOptionView::GetSelectIndex(int index)
{
	if(index == INDEX_CURSEL)
		index = GetCurSel();

	RingOptionItem* item = GetOptionItem(index);
	if(item)
		return item->GetSelectIndex();
	return LB_ERR;
}

int RingOptionView::GetSelectIndex(LPCTSTR lpName)
{
	int index = FindMatchString(lpName);
	
	if(index == LB_ERR)
		return LB_ERR;
	else
		return GetSelectIndex(index);
}

BOOL RingOptionView::SetSelectIndex(int index,int val)
{
	RingOptionItem* item = GetOptionItem(index);
	if(item)
		return item->SetSelectIndex(val);
	return FALSE;
}

BOOL RingOptionView::SetSelectIndex(LPCTSTR lpName,int val)
{
	int index = FindMatchString(lpName);
	
	if(index == LB_ERR)
		return FALSE;
	else
		return SetSelectIndex(index,val);
}

BOOL RingOptionView::SetSelectIndexByData(int index,LONG lData,BOOL IsString/*=FALSE*/)
{
	RingOptionItem* item = GetOptionItem(index);
	if(item)
		return item->SetSelectIndexByData(lData,IsString);
	return FALSE;
}

BOOL RingOptionView::SetSelectIndexByData(LPCTSTR lpName,LONG lData,BOOL IsString/*=FALSE*/)
{
	int index = FindMatchString(lpName);
	
	if(index == LB_ERR)
		return FALSE;
	else
		return SetSelectIndexByData(index,lData,IsString);
}

RingOptionItem* RingOptionView::OnAddString(DWORD type,LPCTSTR lpString)
{	
	RingOptionItem* item = NULL;
	
	if((type & OPTYPE_EXTERN) == OPTYPE_EXTERN)//外部数据
		item = (RingOptionItem*)lpString;

	try
	{
		if(m_fontSubItem.GetFont() == NULL && item && item->IsSubItem())
		{
			LOGFONT hf;
			BOOL bOK = m_fontSubItem.GetWindowLogFont(m_hWnd,&hf);
			if(!bOK)
			{
				m_fontSubItem.SetFont((HFONT)GetStockObject(DEFAULT_GUI_FONT));
				bOK = m_fontSubItem.GetLogFont(&hf);
			}

			if(bOK)
			{
				//hf.lfItalic = TRUE;
				hf.lfUnderline = TRUE;
				m_fontSubItem.SetFont(&hf);
			}
		}
		
		switch(type & OPTYPE_MASK)
		{
			case OPTYPE_LIST:
				if(item == NULL)
				{
					item = new RingOptionItemList;
					item->SetAutoDelete(TRUE);
					item->SetName(lpString);
				}
				if(type & OPTYPE_READONLY)
				{
					if(m_comboSel == NULL)
					{
						m_comboSel = NewRingObj(m_comboSel);
						m_comboSel->Create(WS_CHILD|CBS_AUTOHSCROLL|CBS_DROPDOWNLIST|CBS_HASSTRINGS|WS_BORDER|WS_VSCROLL,WS_EX_CLIENTEDGE,"",LOWORD(m_comboSel),0,0,0,120);
					}
				}
				else
				{
					if(m_combo == NULL)
					{
						m_combo = NewRingObj(m_combo);
						m_combo->Create(WS_CHILD|CBS_AUTOHSCROLL|CBS_DROPDOWN|CBS_HASSTRINGS|WS_BORDER|WS_VSCROLL,WS_EX_CLIENTEDGE,"",LOWORD(m_combo),0,0,0,120);
					}
				}
				break;
			case OPTYPE_BROWSE:
				if(item == NULL)
				{
					item = new RingOptionItemSel;
					item->SetAutoDelete(TRUE);
					item->SetName(lpString);
				}
				if(m_edit == NULL)
				{
					m_edit = NewRingObj(m_edit);
					m_edit->Create(WS_CHILD|ES_AUTOHSCROLL,
						WS_EX_CLIENTEDGE,"",LOWORD(m_edit),0,0,0,0);
					//初始化m_edit的数据缓冲区为1024,否则该缓冲区仅为80字节
					if(m_edit)
						m_edit->GetText(INDEX_CURSEL,1024);
				}
				
				if(m_edit && m_button == NULL)
				{
					m_button = NewRingObj(m_button);
					m_button->Create(WS_CHILD|BS_PUSHBUTTON|BS_TEXT,0,"...",LOWORD(m_button),0,0,0,0);
					m_button->SetFont("宋体",4,FW_BOLD);
					m_button->SetBkColor(GetSysColor(COLOR_BTNFACE));
					m_button->SetExStyle(RINGBTN_EX_NOFOCUSRECT);
				}
				break;
			case OPTYPE_PACK:
				if(item == NULL)
				{
					item = new RingOptionItemPack;
					item->SetAutoDelete(TRUE);
					item->SetName(lpString);
				}
				else
				{
					item->SetParent(this);
					((RingOptionItemPack*)item)->Expand();
				}
				if(m_fontPack.GetFont() == NULL)
				{
					LOGFONT hf;
					BOOL bOK = m_fontPack.GetWindowLogFont(m_hWnd,&hf);
					if(!bOK)
					{
						m_fontPack.SetFont((HFONT)GetStockObject(DEFAULT_GUI_FONT));
						bOK = m_fontPack.GetLogFont(&hf);
					}
					if(bOK)
					{
						hf.lfWeight = FW_BOLD;
						m_fontPack.SetFont(&hf);
					}
				}
				break;
			default:	//默认为OPTYPE_EDIT:
				if(item == NULL)
				{
					item = new RingOptionItemEdit;
					item->SetAutoDelete(TRUE);
					item->SetName(lpString);
				}
				else if((type & OPTYPE_MASK) != OPTYPE_EDIT)
					//外部数据不合要求
					return NULL;

				if(m_edit == NULL)
				{
					m_edit = NewRingObj(m_edit);
					m_edit->Create(WS_CHILD|ES_AUTOHSCROLL,
											WS_EX_CLIENTEDGE,"",LOWORD(m_edit),0,0,0,0);
					//初始化m_edit的数据缓冲区为1024,否则该缓冲区仅为80字节
					if(m_edit)
						m_edit->GetText(INDEX_CURSEL,1024);
				}
				break;							
		}
		//只有是READONLY才需要设置,否则无须改变值,READONLY默认FALSE,
		//如果是SubItem,会调用本函数两次,第二次已无READONLY信息。
		if(item && (type & OPTYPE_READONLY) && (type & OPTYPE_PACK) == 0)
			item->SetReadOnly(TRUE);
	}
	catch(...)
	{
		//出错情况为外部数据或new失败,无须delete item
		return NULL;
	}
	return item;
}

void RingOptionView::OnDelString(int index,DWORD dwFlag)
{
	LONG res = CallWindowProc(m_DefProc,m_hWnd,LB_GETITEMDATA,index,0);
	if(res != LB_ERR && res != 0)
	{
		RingOptionItem* item = (RingOptionItem*)res;
		if(item)
		try
		{
			item->ExitEdit();
			if(item->IsSubItem())
			{
				//数据包子项,先置DATA为0,免发送WM_DELETEITEM消息
				CallWindowProc(m_DefProc,m_hWnd,LB_SETITEMDATA,index,0);
				if(dwFlag == DELITEM_HIDE)
				{
					//数据包收缩,对象仅隐藏不析构,
					item->SetParent(NULL);
				}
				else
				{
					//删除
					RingOptionItemPack* pack = item->m_parentItem;
					if(pack)	//DelSubItem会发送WM_DELETEITEM消息
						pack->DelSubItem(item);
				}
				return;
			}
				
			if(item->IsPackItem())
			{
				((RingOptionItemPack*)item)->Collapse();

				//ResetContent调用时不能调用IsLastPack,因IsLastPack会遍历选项,
				//而此时可能已有选项处于删除状态,其绑定的DATA已变为原设置的DATA,
				//RingOptionItem已删除,无法访问。				
				if(dwFlag != DELITEM_CLEAR && IsLastPack(item))
					SetLeftMargin(0);
			}

			if(item->m_bAutoDelete)
			{
				CallWindowProc(m_DefProc,m_hWnd,LB_SETITEMDATA,index,item->GetData());
				delete item;
			}
			else
				item->SetParent(NULL);
		}
		catch(...)
		{
		}
	}
}

LRESULT RingOptionView::OnDestroy(RINGPARAMS& param)
{
	Clear();
	return DefaultProc(param);
}

BOOL RingOptionView::IsLastPack(RingOptionItem* item)
{
	if(item && item->IsPackItem())
	{
		int cnt = GetCount();
		LONG tmp;

		for(int i=0;i<cnt;i++)
		{
			tmp = CallWindowProc(m_DefProc,m_hWnd,LB_GETITEMDATA,i,0);
			if(tmp != LB_ERR && tmp != NULL && tmp != (LONG)item)
			{
				if(((RingOptionItem*)tmp)->IsPackItem())
					return FALSE;
			}
		}
		return TRUE;
	}
	return FALSE;
}

BOOL RingOptionView::SetValue(int val,int index/*=INDEX_CURSEL*/)
{
	RingOptionItem* item = GetOptionItem(index);
	if(item)
		return item->SetValue(val);
	else
		return FALSE;
}

BOOL RingOptionView::SetValue(LPCTSTR lpszVal,int index/*=INDEX_CURSEL*/)
{
	RingOptionItem* item = GetOptionItem(index);
	if(item)
		return item->SetValue(lpszVal);
	else
		return FALSE;
}

BOOL RingOptionView::SetValue(int index,LPARAM lVal,LPCTSTR szShowVal/*=NULL*/)
{
	RingOptionItem* item = GetOptionItem(index);
	if(item)
		return item->SetValue(lVal,szShowVal);
	else
		return FALSE;
}

BOOL RingOptionView::SetValue(LPCTSTR szItemName,LPARAM lVal,LPCTSTR szShowVal/*=NULL*/)
{	
	return SetValue(FindMatchString(szItemName),lVal,szShowVal);	
}

//设置数据包子项数据
BOOL RingOptionView::SetPackItemValue(int index,LPCTSTR szSubItem,LPARAM lVal,LPCTSTR szShowVal/*=NULL*/)
{
	return SetPackItemValue(GetPackItem(index),szSubItem,lVal,szShowVal);
}

BOOL RingOptionView::SetPackItemValue(LPCTSTR szPackName,LPCTSTR szSubItem,LPARAM lVal,LPCTSTR szShowVal/*=NULL*/)
{
	return SetPackItemValue(GetPackItem(szPackName),szSubItem,lVal,szShowVal);
}

BOOL RingOptionView::SetPackItemValue(RingOptionItemPack* pack,LPCTSTR szSubItem,LPARAM lVal,LPCTSTR szShowVal/*=NULL*/)
{
	if(pack)
	{
		RingOptionItem* item = GetOptionItem(szSubItem);
		if(item == NULL || !item->IsSubItem() || item->m_parentItem != pack)
			//包可能已收起,遍历寻找
			item = pack->GetSubItem(szSubItem);
		
		if(item)
			return item->SetValue(lVal,szShowVal);		
	}
	return FALSE;
}

//获取数据包子项数据,数据包有可能收起,调用GetText和GetInt会失败或得不到
//正确值,GetPackItemText和GetPackItemInt不管数据包是否收起总能获得正确值
LPCTSTR RingOptionView::GetPackItemText(int index,LPCTSTR szSubItem)
{
	return GetPackItemText(GetPackItem(index),szSubItem);
}

LPCTSTR RingOptionView::GetPackItemText(LPCTSTR szPackName,LPCTSTR szSubItem)
{
	return GetPackItemText(GetPackItem(szPackName),szSubItem);
}

LPCTSTR RingOptionView::GetPackItemText(RingOptionItemPack* pack,LPCTSTR szSubItem)
{
	if(pack)
	{
		RingOptionItem* item = pack->GetSubItem(szSubItem);
		
		if(item)
			return item->GetText();
	}
	return "";
}

int RingOptionView::GetPackItemInt(int index,LPCTSTR szSubItem)
{
	return GetPackItemInt(GetPackItem(index),szSubItem);
}

int RingOptionView::GetPackItemInt(LPCTSTR szPackName,LPCTSTR szSubItem)
{
	return GetPackItemInt(GetPackItem(szPackName),szSubItem);
}

int RingOptionView::GetPackItemInt(RingOptionItemPack* pack,LPCTSTR szSubItem)
{
	if(pack)
	{
		RingOptionItem* item = pack->GetSubItem(szSubItem);
		
		if(item)
			return item->GetInt();
	}
	return 0;
}

//加入属性设置
int RingOptionView::AddOption(LPCTSTR szOption,LPCTSTR szDefValue/*=NULL*/,
										LPARAM lParam/*=0*/,UINT uEditType/*=OPTYPE_EDIT*/,
										LONG lTypeCfg/*=0*/)
{
	int index = SendMessage(m_hWnd,LB_ADDSTRING,(uEditType<<16),(LPARAM)szOption);
	if(index >= 0)
	{
		RingOptionItem* item = GetOptionItem(index);
		if(item)
		{
			item->SetOption(lTypeCfg);
			item->InterSetValue(lParam,szDefValue);
		}
	}
	return index;
}

int RingOptionView::AddOptionPack(LPCTSTR szOption,LPARAM lParam/*=0*/)
{
	int index = SendMessage(m_hWnd,LB_ADDSTRING,(OPTYPE_PACK<<16),(LPARAM)szOption);
	if(index >= 0)
	{
		RingOptionItem* item = GetOptionItem(index);
		if(item)
			item->InterSetValue(lParam,NULL);
	}
	return index;
}

int RingOptionView::AddOption(RingOptionItem* item)
{
	//已加入到OptionView中的项目不能再加入
	if(item && item->GetParent() == NULL)
		return SendMessage(m_hWnd,LB_ADDSTRING,((item->GetType()|OPTYPE_EXTERN)<<16),(LPARAM)item);
	else
		return LB_ERR;
}

int RingOptionView::InsertOption(int index,LPCTSTR szOption,LPCTSTR szDefValue/*=NULL*/,
											LPARAM lParam/*=0*/,UINT uEditType/*=OPTYPE_EDIT*/,
											LONG lTypeCfg/*=0*/)
{
	int idx = SendMessage(m_hWnd,LB_INSERTSTRING,MAKELONG(index,uEditType),(LPARAM)szOption);
	if(index >= 0)
	{
		RingOptionItem* item = GetOptionItem(idx);
		if(item)
		{
			item->SetOption(lTypeCfg);
			item->InterSetValue(lParam,szDefValue);
		}
	}
	return idx;
}

int RingOptionView::InsertOption(RingOptionItem* item,int index)
{
	if(index == INDEX_CURSEL)
		return AddOption(item);
	else if(item && item->GetParent() == NULL)
		return SendMessage(m_hWnd,LB_INSERTSTRING,((item->GetType()|OPTYPE_EXTERN)<<16) + LOWORD(index),(LPARAM)item);
	else
		return LB_ERR;
}

int RingOptionView::InsertOption(RingOptionItem* item,LPCTSTR lpString)
{
	if(item && lpString)
	{
		int index = FindMatchString(lpString);
		return InsertOption(item,index);
	}
	else
		return LB_ERR;
}

int RingOptionView::AddSubOption(LPCTSTR szPackName,LPCTSTR szOption,
											LPCTSTR szDefValue/*=NULL*/,
											LPARAM lParam/*=0*/,
											UINT uEditType/*=OPTYPE_EDIT*/,
											LONG lTypeCfg/*=0*/)
{
	//取消包属性
	if((uEditType & OPTYPE_PACK))
		return LB_ERR;

	RingOptionItemPack* item = GetPackItem(szPackName);
	if(item)
	{
		RingOptionItem* subitem = OnAddString(uEditType,szOption);
		if(subitem)
		{
			subitem->SetOption(lTypeCfg);
			subitem->InterSetValue(lParam,szDefValue);
			return item->AddSubItem(subitem);
		}
	}
	return LB_ERR;
}

int RingOptionView::AddSubOption(int index,LPCTSTR szOption,LPCTSTR szDefValue/*=NULL*/,
											LPARAM lParam/*=0*/,UINT uEditType/*=OPTYPE_EDIT*/,
											LONG lTypeCfg/*=0*/)
{
	//取消包属性
	if((uEditType & OPTYPE_PACK))
		return LB_ERR;
	
	RingOptionItemPack* item = GetPackItem(index);
	if(item)
	{
		RingOptionItem* subitem = OnAddString(uEditType,szOption);
		if(subitem)
		{
			subitem->SetOption(lTypeCfg);
			subitem->InterSetValue(lParam,szDefValue);
			return item->AddSubItem(subitem);
		}
	}
	return LB_ERR;
}

int RingOptionView::DelOption(RingOptionItem* item)
{
	if(item)
		return DelString(item->GetName());
	else
		return LB_ERR;
}

int RingOptionView::ClearPack(int index)
{
	RingOptionItem* item = GetOptionItem(index);
	if(item->IsPackItem())
	{
		RingOptionItemPack* pack = (RingOptionItemPack*)item;
		pack->Collapse();
		pack->Clear();
		return TRUE;
	}
	return LB_ERR;
}

int RingOptionView::ClearPack(LPCTSTR lpName)
{
	return ClearPack(FindMatchString(lpName));
}

//清空数据,保留各子项,设置各项值为空,保留列表子项的列表选项
void RingOptionView::Reset()
{
	RingOptionItem* item;

	for(int i=0;i<GetCount();i++)
	{
		item = GetOptionItem(i);
		//SubItem不需要Reset,由PackItem遍历后Reset
		if(item && !item->IsSubItem())
			item->Reset();
	}
}

BOOL RingOptionView::SetItemValChangeFunc(int index,RINGVCLASS* obj,ROPV_CHECKVALFUNC func)
{
	RingOptionItem* item = GetOptionItem(index);
	if(item)
	{
		item->SetCheckValueFunc(obj,func);
		return TRUE;
	}
	return FALSE;
}

BOOL RingOptionView::SetItemValChangeFunc(LPCTSTR lpName,RINGVCLASS* obj,ROPV_CHECKVALFUNC func)
{
	int index = FindMatchString(lpName);
	
	if(index == LB_ERR)
		return FALSE;
	else
		return SetItemValChangeFunc(index,obj,func);
}

BOOL RingOptionView::SetItemValSelectFunc(int index,RINGVCLASS* obj,ROPV_CHECKVALFUNC func)
{
	RingOptionItem* item = GetOptionItem(index);
	if(item)
		return item->SetSelChangeFunc(obj,func);
	else
		return FALSE;
}

BOOL RingOptionView::SetItemValSelectFunc(LPCTSTR lpName,RINGVCLASS* obj,ROPV_CHECKVALFUNC func)
{
	int index = FindMatchString(lpName);
	
	if(index == LB_ERR)
		return FALSE;
	else
		return SetItemValSelectFunc(index,obj,func);
}

BOOL RingOptionView::SetItemBrowserFunc(int index,RINGVCLASS* obj,ROPV_CHECKVALFUNC func)
{
	RingOptionItem* item = GetOptionItem(index);
	if(item)
		return item->SetBrowserFunc(obj,func);
	else
		return FALSE;
}

BOOL RingOptionView::SetItemBrowserFunc(LPCTSTR lpName,RINGVCLASS* obj,ROPV_CHECKVALFUNC func)
{
	int index = FindMatchString(lpName);
	
	if(index == LB_ERR)
		return FALSE;
	else
		return SetItemBrowserFunc(index,obj,func);
}

/**********************************************************
//
//RingOptionItem
//
***********************************************************/
void RingOptionItem::DrawValue(HDC hDC,LPRECT lprc)
{
	if(m_edit == NULL)
		DrawText(hDC,GetText(),m_strValue.len(),lprc,DT_LEFT);
}

//得到在OptionView中的排列序号(数据包子项返回LB_ERR)
int RingOptionItem::GetIndex()
{	
	if(m_parent && !IsSubItem())
	{
		int start,index = -1;
		RingOptionItem* item = NULL;

		do
		{
			start = index;
			index = m_parent->FindMatchString(m_strName.string(),start);
			if(index != LB_ERR)
				item = m_parent->GetOptionItem(index);
			else
				return LB_ERR;
		}while(item != this && index > start);

		if(item == this)
			return index;
	}
	return LB_ERR;
}

//得到在数据包中的排列序号
int RingOptionItem::GetSubIndex(RingOptionItemPack** parentItem/*=NULL*/)
{	
	if(parentItem)
		*parentItem = m_parentItem;
	
	if(IsSubItem() && m_parentItem)
		return m_parentItem->GetSubItemIndex(m_strName.string());
	
	return LB_ERR;
}

LPCTSTR RingOptionItem::GetText()
{
	if(m_edit)
		return m_edit->GetText();
	else
		return m_strValue.string();
}

int RingOptionItem::GetInt()
{
	if(m_edit)
		return m_edit->GetInt();
	else
		return m_strValue.toInt();
}	

void RingOptionItem::ActiveOption(RingControls& edit)
{
	edit.SetReadOnly(m_bReadOnly);
}

void RingOptionItem::EnterEdit(int x,int y,int width,int height)
{	
	if(m_edit)
	{
		//MoveWindow(m_edit->Handle(),x,y,width,height,FALSE);
		ActiveOption(*m_edit);
		m_edit->SetPos(x,y,width,height);		
		
		if(!m_edit->IsVisible())
			m_edit->Show();
	}
	else
	{
		m_edit = GetEditCtrl();
		if(m_edit)
		{
			ActiveOption(*m_edit);
			m_edit->SetPos(x,y,width,height);
			if(m_strValue.isClear())
				m_edit->SetValue("");
			else
			{
				m_edit->SetValue(m_strValue.string());
				if(m_edit->GetWindowType() == ITIS_EDIT)
					((RingEdit*)m_edit)->SetSel();
			}
			m_edit->Show();
			m_edit->SetFocus();
		}
	}
}

/////////////////////////////////////////////////
//
//隐藏编辑控件,需要执行绑定的处理函数或发送
//ROPVN_VALUECHANGE消息通知值已改变,并保存处理后的结果.
//
/////////////////////////////////////////////////
BOOL RingOptionItem::ExitEdit()
{
	BOOL bok = FALSE;

	if(m_edit)
	{		
		bok = TRUE;
		try
		{
			if(m_strValue != m_edit->GetText())
			{
				if(m_obj && m_OnCheckValFunc)
					bok = (m_obj->*(m_OnCheckValFunc))(this);
				else
				{
					ROPVNOTIFY opnm;
					
					opnm.hdr.code = ROPVN_VALUECHANGE;
					opnm.hdr.hwndFrom = m_parent->Handle();
					opnm.hdr.idFrom = m_parent->GetId();
					opnm.item = this;
					opnm.lpszOrgText = m_strValue.string();
					opnm.lpszName = GetName();
					opnm.lpszText = m_edit->GetText();
					opnm.lValue = GetInt();
					opnm.lData = GetData();
					opnm.uType = GetType();
					//如果父窗口未对该事件进行处理,SendMessage返回0,因此需置
					//bok为真,允许修改值。父窗口如对该事件进行处理,认为输入值
					//非法,不允许改变必须返回-1,返回其他值则允许修改。					
					if(SendMessage(m_parent->Parent()->Handle(),WM_NOTIFY,
											m_parent->GetCurSel(),(LPARAM)&opnm) == -1)
						bok = FALSE;
					else
						bok = TRUE;
				}
			}
		}
		catch(...)
		{
		}

		if(bok)
			m_strValue = m_edit->GetText();
		else
			m_edit->SetValue(m_strValue.string());

		m_edit->Show(SW_HIDE);		
	}
	m_edit = NULL;
	return bok;
}

void RingOptionItem::UpdateValue()
{
	if(m_edit)
		m_strValue = m_edit->GetText();
}

BOOL RingOptionItem::IsEditVisible()
{
	if(m_edit)
	{
		RECT rc;
		m_edit->GetRect(&rc);
		return (rc.top >= 0 && rc.top < m_edit->Parent()->Height());
	}
	return FALSE;
}

BOOL RingOptionItem::SetValue(int nVal)
{
	m_strValue = nVal;
	if(m_edit)
		return m_edit->SetValue(m_strValue.string());
	else if(m_parent)
		InvalidateRect(m_parent->Handle(),NULL,TRUE);
	return TRUE;
}

BOOL RingOptionItem::SetValue(LPCTSTR lpszVal)
{
	if(lpszVal)
	{
		m_strValue = lpszVal;
		if(m_edit)
			return m_edit->SetValue(lpszVal);
		else if(m_parent)
			InvalidateRect(m_parent->Handle(),NULL,TRUE);
		return TRUE;
	}
	return FALSE;
}

BOOL RingOptionItem::SetValue(LPARAM lVal,LPCTSTR lpszShowVal)
{
	SetData(lVal);
	if(lpszShowVal)
		return SetValue(lpszShowVal);
	else	//lpszShowVal为空,不改变显示值,返回TRUE
		return TRUE;
}

/**********************************************************
//
//RingOptionItemEdit
//
***********************************************************/
void RingOptionItemEdit::ActiveOption(RingControls& edit)
{	
	RingOptionItem::ActiveOption(edit);
	
	if(m_uType & OPPROP_NUMBERONLY)
		edit.ReplaceStyle(0,ES_NUMBER);
	else
		edit.ReplaceStyle(ES_NUMBER,0);
	if(m_uType & OPPROP_PASSWORD)
		SendMessage(edit.Handle(),EM_SETPASSWORDCHAR,(WPARAM)'*',0);
	else
		SendMessage(edit.Handle(),EM_SETPASSWORDCHAR,0,0);
}

void RingOptionItemEdit::DrawValue(HDC hDC,LPRECT lprc)
{
	if(m_edit == NULL)
	{
		if(m_strPsw && (m_uType & OPPROP_PASSWORD))
			DrawText(hDC,m_strPsw->string(),m_strPsw->len(),lprc,DT_LEFT);
		else
			DrawText(hDC,GetText(),m_strValue.len(),lprc,DT_LEFT);
	}
}

///////////////////////////////////////////////////////
//
//ExitEdit为给用户判断是否允许改变值,并保存处理后的结果。
//而OnBeforeNotify由RingOptionView::SendNotify调用,目的是
//当编辑控件是LIST或有按钮时检测是否绑定了SelChangeFunc和
//BrowserFunc,以给机会执行这些函数,EDIT无这两个函数,但
//需要判断是否允许改变值,因为ExitEdit无法捕获所有值改变的
//情况,只有EN_KILLFOCUS消息能捕获,因此这里需要调用CheckValFunc
//或发送ROPVN_VALUECHANGE消息给用户判断是否允许改变值,并
//保存处理后的结果,完成了ExitEdit的功能。由于OnBeforeNotify
//是执行绑定函数,无绑定函数则返回FALSE以发送相应通知消息,
//而EDIT没有这两个消息,因此始终返回TRUE,不发送消息。
//
///////////////////////////////////////////////////////
BOOL RingOptionItemEdit::OnBeforeNotify(int type)
{
	if(type == ROPVN_VALUECHANGE && m_strValue != m_edit->GetText())
	{
		BOOL bok;
		
		if(m_obj && m_OnCheckValFunc)
			bok = (m_obj->*(m_OnCheckValFunc))(this);
		else
		{
			ROPVNOTIFY opnm;
			
			opnm.hdr.code = ROPVN_VALUECHANGE;
			opnm.hdr.hwndFrom = m_parent->Handle();
			opnm.hdr.idFrom = m_parent->GetId();
			opnm.item = this;
			opnm.lpszOrgText = m_strValue.string();
			opnm.lpszName = GetName();
			opnm.lpszText = m_edit->GetText();
			opnm.lValue = GetInt();
			opnm.lData = GetData();
			opnm.uType = GetType();
			//如果父窗口未对该事件进行处理,SendMessage返回0,因此需置
			//bok为真,允许修改值。父窗口如对该事件进行处理,认为输入值
			//非法,不允许改变必须返回-1,返回其他值则允许修改。					
			if(SendMessage(m_parent->Parent()->Handle(),WM_NOTIFY,
				m_parent->GetCurSel(),(LPARAM)&opnm) == -1)
				bok = FALSE;
			else
				bok = TRUE;
		}
		if(bok)
			m_strValue = m_edit->GetText();
		else
			m_edit->SetValue(m_strValue.string());
	}
	return TRUE;
}

BOOL RingOptionItemEdit::ExitEdit()
{
	//值改变判断已由OnBeforeNotify执行,这里只需简单隐藏即可
	if(m_edit)
	{		
		m_strValue = m_edit->GetText();
		m_edit->Show(SW_HIDE);		
	}
	m_edit = NULL;

	if(m_strPsw && (m_uType & OPPROP_PASSWORD))
	{
		*m_strPsw = m_strValue;
		memset((LPSTR)m_strPsw->string(),'*',m_strPsw->len());
	}
	return TRUE;
}

BOOL RingOptionItemEdit::SetValue(int nVal)
{
	if((m_uType & OPPROP_PASSWORD))
	{
		if(m_strPsw == NULL)
			m_strPsw = new ringStr;
		if(m_strPsw)
		{
			*m_strPsw = nVal;
			memset((LPSTR)m_strPsw->string(),'*',m_strPsw->len());
		}
	}
	return RingOptionItem::SetValue(nVal);
}

BOOL RingOptionItemEdit::SetValue(LPCTSTR lpszVal)
{
	if((m_uType & OPPROP_PASSWORD))
	{
		if(m_strPsw == NULL)
			m_strPsw = new ringStr;
		if(m_strPsw)
		{
			*m_strPsw = lpszVal;
			memset((LPSTR)m_strPsw->string(),'*',m_strPsw->len());
		}
	}
	return RingOptionItem::SetValue(lpszVal);
}

/**********************************************************
//
//RingOptionItemList
//
***********************************************************/
BOOL RingOptionItemList::InterSetValue(LPARAM lVal,LPCTSTR lpszShowVal)
{
	SetData(lVal);
	m_strValue = lpszShowVal;
	if(m_edit)
	{
		((RingCombo*)m_edit)->AddStrings(m_strList.string());
		m_edit->SetValue(lpszShowVal);
	}
	return TRUE;
}

//返回显示值
LPCTSTR RingOptionItemList::GetText()
{
	if(m_edit)
	{
		RingCombo* combo = (RingCombo*)m_edit;
		int index = combo->GetCurSel();
		if(index == CB_ERR)
			return combo->GetText();
		else
			return combo->GetLBText(index);
	}
	else
		return m_strValue.string();
}

//得到当前选择项对应的数据,如没有设置过隐含值,返回0
//本函数不返回显示值的转换数字值
int RingOptionItemList::GetInt()
{
	if(m_strList.isClear() || m_selData == NULL)
		return 0;
		
	if(m_edit)
	{
		RingCombo* combo = (RingCombo*)m_edit;
		if(combo->GetCurSel() != CB_ERR)
			return combo->GetData(combo->GetCurSel());
		else
			return 0;
	}
	else
		return GetItemData();		
}

BOOL RingOptionItemList::SetValue(int nVal)
{
	if(IsReadOnly())
		return SetSelectIndex(nVal);
	else
		return RingOptionItem::SetValue(nVal);
}

BOOL RingOptionItemList::SetValue(LPCTSTR lpszVal)
{
	if(IsReadOnly() && FindString(lpszVal) == LB_ERR)
		return FALSE;
	else
		return RingOptionItem::SetValue(lpszVal);
}

int RingOptionItemList::GetSelectIndex()
{
	if(m_strList.isClear())
		return LB_ERR;
				
	if(m_edit)
		return ((RingCombo*)m_edit)->GetCurSel();
	else
		return FindString(m_strValue.string());
	return LB_ERR;
}

//在选项中查找lpString,必须完全匹配,即该选项必须前后有"|"分隔符,
//但最前和最后一个选项要一些特殊判断,返回lpString所在选项序号
int RingOptionItemList::FindString(LPCTSTR lpString)
{
	if(lpString == NULL || *lpString == '\0' || m_strList.isClear())
		return LB_ERR;

	if(m_edit)
		return ((RingCombo*)m_edit)->FindMatchString(lpString);
	else
	{
		int index = 0;
		int len = lstrlen(lpString),pos = 0;

		do 
		{
			pos = m_strList.indexOf(lpString,pos) + 1;
			if(pos == 0)	 //indexOf返回-1表示未找到,+1后=0
				return LB_ERR;
		}while(!((pos == 1 || m_strList[pos - 2] == _T('|')) && 
			(m_strList[(int)(pos + len - 1)] == _T('|') || 
			m_strList.len() == pos + len - 1)));//必须全部匹配
		
		if(pos == 1)
			return 0;
		else
		{
			len = 1;
			do
			{
				len = m_strList.indexOf("|",len) + 1;
				index ++;
			}while(len != pos - 1 && len != 0);
			return index;
		}
	}
	return LB_ERR;
}

BOOL RingOptionItemList::SetSelectIndex(int index)
{
	if(m_strList.isClear() || index < 0 || index >= m_nItemCnt)
		return FALSE;
		
	if(m_edit)
		return ((RingCombo*)m_edit)->Select(index);
	else
	{
		if(index > 0)
		{
			index = m_strList.indexOf("|",0,index);
			if(index == -1)
				return FALSE;
			else
				index ++;
		}

		int e = m_strList.indexOf("|",index);
		if(e == -1)
			e = m_strList.len();
		if(e <= index)
			return FALSE;
		else
		{
			m_strValue = m_strList.SubString(index,e-index);
			if(m_parent)
				InvalidateRect(m_parent->Handle(),NULL,TRUE);
		}
	}
	return TRUE;
}

//根据绑定值设置选项
BOOL RingOptionItemList::SetSelectIndexByData(LONG lData)
{
	if(m_strList.isClear() || m_selData == NULL)
		return FALSE;
		
	int index = -1;
	for(int i=0;i<m_nItemCnt;i++)
	{
		if(m_selData[i] == lData)
		{
			index = i;
			break;
		}
	}
	return SetSelectIndex(index);
}

void RingOptionItemList::EnterEdit(int x,int y,int width,int height)
{
	//由于WM_DRAWITEM也会调用本函数,RingOptionItem::EnterEdit执行过后
	//m_edit && m_edit->IsVisible()条件会成立,因此下面的这个if...else
	//必须如此判断,不可优化为先执行EnterEdit再判断,否则判断永远成立。
	if(m_edit && m_edit->IsVisible())
	{
		RingOptionItem::EnterEdit(x,y,width,height);
		return;
	}
	else
		RingOptionItem::EnterEdit(x,y,width,height);
	
	RingCombo* combo = (RingCombo*)m_edit;
	if(combo)
	{
		combo->Clear();
		if(!m_strList.isClear())
		{
			combo->AddStrings(m_strList.string());
			//设置选项数据
			if(m_selData)
			{
				for(int i=0;i<m_nItemCnt;i++)
					combo->SetData(i,m_selData[i]);
			}
			combo->SetValue(m_strValue.string());
		}
	}
}

//设置选项,必须先清除全部选项才可调用
BOOL RingOptionItemList::SetSelection(LPCTSTR lpString)
{
	if(lpString && m_strList.isClear())
	{
		m_strList = lpString;
		m_nItemCnt = m_strList.count(_T("|")) + 1;
		if(m_edit)
		{
			((RingCombo*)m_edit)->Clear();
			((RingCombo*)m_edit)->AddStrings(lpString);
		}
		return TRUE;
	}
	else
		return FALSE;
}

BOOL RingOptionItemList::AddSelection(LPCTSTR lpString,LONG lData)
{
	if(lpString)
	{
		if(m_strList.isClear())
			m_strList = lpString;
		else
			m_strList = m_strList + _T("|") + lpString;

		m_nItemCnt ++;

		if(lData != 0)
			SetItemData(lData,m_nItemCnt-1);

		if(m_edit)
			((RingCombo*)m_edit)->AddString(lpString,lData);
		return TRUE;
	}
	else
		return FALSE;
}

void RingOptionItemList::SetItemData(LPARAM lParam,int index)
{
	LPLONG lpl = m_selData;
	int nSize = 0;
	if(m_selData == NULL || m_nItemCnt > m_nDataSize)
	{
		nSize = m_nDataSize;
		m_nDataSize = m_nItemCnt + 1;
		m_selData = (LPLONG)New(sizeof(LONG) * m_nDataSize);
	}
	if(m_selData)
	{
		if(lpl && nSize > 0)
		{
			memcpy(m_selData,lpl,nSize*sizeof(LONG));
			Del(lpl);
		}

		if(index >= 0 && index < m_nItemCnt)
			m_selData[index] = lParam;
	}
	else
		m_nDataSize = 0;
}

BOOL RingOptionItemList::DelSelection(LPCTSTR lpString)
{
	if(lpString)
	{
		int index = FindString(lpString);
		if(index != LB_ERR)
		{
			m_strList = m_strList.replace(lpString,"");
			m_strList = m_strList.replace("||","|");
			if(m_strList[m_strList.len()-1] == '|')
			{
				m_strList[m_strList.len()-1] = '\0';
				m_strList.GetLength();
			}
			if(m_edit)
				((RingCombo*)m_edit)->DelString(lpString);

			m_nItemCnt --;
			if(m_selData)
			{
				//后面的数据往前移
				for(int i=index;i<m_nItemCnt;i++)
					m_selData[i] = m_selData[i+1];
				m_selData[i] = 0;
			}
			if(IsReadOnly() && m_strValue == lpString)
			{
				m_strValue.Clear();
				if(m_parent)
					InvalidateRect(m_parent->Handle(),NULL,TRUE);
			}
			return TRUE;
		}
	}
	return FALSE;
}

void RingOptionItemList::Clear()
{
	if(m_selData && m_nDataSize > 0)
		RtlZeroMemory(m_selData,m_nDataSize);

	m_strList.Clear();

	if(m_edit)
		m_edit->Clear();
	if(m_parent)
		InvalidateRect(m_parent->Handle(),NULL,TRUE);
}

BOOL RingOptionItemList::SetOption(LONG lConfig)
{
	try
	{
		ringStr str = (LPSTR)lConfig;
		int pos = str.indexOf("||");
		if(pos > 0)
		{
			m_strList = str.SubString(0,pos);
			m_nItemCnt = m_strList.count("|") + 1;

			ringStr strData = str.SubString(pos + 2);
			int i,c = 0;
			LPTSTR s;

			for(i=0;i<m_nItemCnt;i++)
			{ 
				s = (LPTSTR)strData.string() + c;
				c = strData.indexOf("|",c) + 1;
				
				//str的operator[]总是安全的,如果是\,表示该|字符是经转义,不作为分隔符
				if(strData[c-2] == '\\')
					continue;
				strData[c-1] = '\0';
				if(*s != '\0')
					SetItemData(atoi(s),i);
			}
		}
		else
		{
			m_strList = str;
			m_nItemCnt = m_strList.count("|") + 1;
		}
		return TRUE;
	}
	catch(...)
	{
		return FALSE;
	}
}

BOOL RingOptionItemList::OnBeforeNotify(int type)
{
	if(type == ROPVN_SELCHANGE)
	{
		if(m_objSel && m_SelectFunc)
		{
			(m_objSel->*(m_SelectFunc))(this);
			return TRUE;
		}
	}
	return FALSE;
}

LONG RingOptionItemList::GetItemData(int index)
{
	if(index == INDEX_CURSEL)
		index = FindString(m_strValue.string());
			
	if(index >= 0 && index < m_nItemCnt && m_selData)
		return m_selData[index];
	else
		return 0;
}

/**********************************************************
//
//RingOptionItemSel
//
***********************************************************/
void RingOptionItemSel::EnterEdit(int x,int y,int width,int height)
{	
	RingOptionItem::EnterEdit(x,y,width-height+1,height);
	
	if(m_button)
	{
		if(!m_button->IsVisible())
			m_button->Show();
		//MoveWindow(m_button->Handle(),x+width-height+1,y+1,height-2,height-2,FALSE);
		m_button->SetPos(x+width-height+1,y+1,height-2,height-2);
	}
	else
	{
		m_button = GetParent()?GetParent()->GetButton():NULL;
		if(m_button)
		{
			//m_button->SetParent(m_edit->Handle());
			//MoveWindow(m_button->Handle(),x+width-height+1,y+1,height-2,height-2,FALSE);
			m_button->SetPos(x+width-height+1,y+1,height-2,height-2);
		}
	}
}

//返回值仅RingOptionItem::ExitEdit()有意义,供RingOptionItem::ExitEdit()判断使用
//这里返回FALSE
BOOL RingOptionItemSel::ExitEdit()
{
	RingOptionItem::ExitEdit();

	if(m_button)
	{
		m_button->Show(SW_HIDE);
	}
	m_button = NULL;
	return FALSE;
}

BOOL RingOptionItemSel::OnBeforeNotify(int type)
{
	if(type == ROPVN_BUTTONCLICK)
	{
		if(m_bIsSelectFile)
		{
			ringFile rf;
			if(rf.Select(m_szFileExt))
				SetValue(rf.Fullname());
			return TRUE;
		}
		else
		{
			if(m_objBrowser && m_BrowserFunc)
			{
				(m_objBrowser->*(m_BrowserFunc))(this);
				return TRUE;
			}
		}
	}
	return FALSE;
}
/*
BOOL RingOptionItemSel::SetValue(LPARAM lVal,LPCTSTR lpszShowVal)
{
	SetItemData(lVal);
	if(lpszShowVal)
		return SetValue(lpszShowVal);
	else
		return TRUE;
}
*/
BOOL RingOptionItemSel::SetOption(LONG lConfig)
{
	try
	{
		if(lConfig)
		{
			memset(m_szFileExt,0,80);
			lstrcpyn(m_szFileExt,(LPCTSTR)lConfig,79);
			m_bIsSelectFile = TRUE;			
		}
		else
			m_bIsSelectFile = FALSE;
		return TRUE;
	}
	catch(...)
	{
	}
	return FALSE;
}

/**********************************************************
//
//RingOptionItemPack
//
***********************************************************/
RingOptionItemPack::RingOptionItemPack()
{
	m_SubItem = NULL;
	m_bExpand = TRUE;
}

RingOptionItemPack::~RingOptionItemPack()
{
	Clear();
}

void RingOptionItemPack::Clear()
{
	LPRPDATAPACKITEM save,tmp = m_SubItem;
	HWND hWnd = NULL;
	DELETEITEMSTRUCT ds;
	int index = 0;

	if(m_parent && IsWindowPtr(m_parent->Parent()))
	{
		hWnd = m_parent->Parent()->Handle();
		ds.CtlID = GetIndex();
		ds.CtlType = ODT_LISTBOX;
		ds.hwndItem = m_parent->Handle();
	}

	while(tmp)
	{
		if(tmp->m_item && tmp->m_item->m_bAutoDelete)
		{
			if(hWnd)
			{
				ds.itemID = index;
				ds.itemData = tmp->m_item->GetData();
				if(ds.itemData != 0)
					SendMessage(hWnd,WM_DELETEITEM,m_parent->GetId(),(LPARAM)&ds);
			}
			delete tmp->m_item;
		}
		save = tmp->m_next;
		Del(tmp);
		tmp = save;
	}
	m_SubItem = NULL;
}

void RingOptionItemPack::Reset()
{
	LPRPDATAPACKITEM tmp = m_SubItem;
	
	while(tmp)
	{
		if(tmp->m_item)
			tmp->m_item->Reset();
		tmp = tmp->m_next;		
	}	
}

void RingOptionItemPack::DrawValue(HDC hDC,LPRECT lprc)
{
	if(lprc && m_SubItem)
	{		
		lprc->left = (m_parent->GetLeftMargin() - 8) / 2;
		lprc->right = lprc->left + 9;
		lprc->top = (lprc->bottom + lprc->top - 9)/2 - 1;
		lprc->bottom = lprc->top + 9;

		if(lprc->right <= 0)
			return;

		FrameRect(hDC,lprc,(HBRUSH)GetStockObject(BLACK_BRUSH));

		SelectObject(hDC,(HBRUSH)GetStockObject(BLACK_PEN));
		MoveToEx(hDC,lprc->left + 2,lprc->top + 4,NULL);
		LineTo(hDC,lprc->left + 7,lprc->top + 4);
		if(!m_bExpand)
		{
			MoveToEx(hDC,lprc->left + 4,lprc->top + 2,NULL);
			LineTo(hDC,lprc->left + 4,lprc->top + 7);
		}
	}
}

void RingOptionItemPack::Expand()
{	
	if(m_SubItem && !m_bExpand && m_parent)
	{
		LPRPDATAPACKITEM tmp = m_SubItem;
		int index,org = GetIndex();//m_parent->FindMatchString(m_strName.string());
		m_bExpand = TRUE;
		index = org;
		while(index != LB_ERR && index != LB_ERRSPACE)
		{
			index ++;
			if(tmp->m_item)
				index = m_parent->InsertOption(tmp->m_item,index);
			if(tmp->m_next)
				tmp = tmp->m_next;
			else
			{
				//调整LISTBOX使整个包可见
				int n = m_parent->Height() / m_parent->GetItemHeight();
				int h = m_parent->GetTopIndex();
				if(index - h > n)
				{
					index = (index - org) > n?org:(index - n + 1);
					m_parent->SetTopIndex(index);
					m_parent->SetCurSel(org);
				}
				break;
			}
		}
	}
}

void RingOptionItemPack::Collapse()
{
	if(m_parent && m_bExpand)
	{
		LPRPDATAPACKITEM tmp = m_SubItem;
		int index = GetIndex();
		m_bExpand = FALSE;

		if(index != LB_ERR)
		{
			index ++;
			while(tmp)
			{
				if(tmp->m_item && tmp->m_item->GetParent())
					SendMessage(m_parent->Handle(),LB_DELETESTRING,index,DELITEM_HIDE);
				tmp = tmp->m_next;
			}
		}
	}
}

void RingOptionItemPack::AutoExpand()
{
	if(m_bExpand)
		Collapse();
	else
		Expand();
}

int RingOptionItemPack::AddSubItem(RingOptionItem* item)
{
	if(item)
	{		
		//已加入到OptionView中的项目不能再加入
		if(item->GetParent())
			return LB_ERR;

		LPRPDATAPACKITEM prev = NULL,tmp = m_SubItem;
		int cnt = 0;

		while(tmp)
		{
			prev = tmp;
			tmp = tmp->m_next;
			cnt ++;
		}

		if(prev == NULL)
		{
			m_SubItem = (LPRPDATAPACKITEM)New(sizeof(RPDATAPACKITEM));
			prev = m_SubItem;
			if(m_parent)
			{
				m_parent->SetLeftMargin(ROPV_LEFTMARGIN);
				InvalidateRect(m_parent->Handle(),NULL,TRUE);
			}
		}
		else
		{
			prev->m_next = (LPRPDATAPACKITEM)New(sizeof(RPDATAPACKITEM));
			prev = prev->m_next;
		}
		
		prev->m_item = item;
		item->m_parentItem = this;

		if(m_bExpand && m_parent)
		{
			int index = GetIndex();
			if(index != LB_ERR)
				return m_parent->InsertOption(item,index + cnt + 1);
		}
		return -(1000 + cnt);
	}
	return LB_ERR;
}

BOOL RingOptionItemPack::DelSubItem(RingOptionItem* item)
{
	if(item && item->m_parentItem == this)
	{		
		LPRPDATAPACKITEM prev = NULL,tmp = m_SubItem;
		int index = 0;
		DELETEITEMSTRUCT ds;

		while(tmp && tmp->m_item != item)
		{
			prev = tmp;
			tmp = tmp->m_next;
			index ++;
		}
		if(tmp == NULL)
			return FALSE;

		if(prev == NULL)
			m_SubItem = m_SubItem->m_next;
		else
			prev->m_next = tmp->m_next;
		
		item->m_parentItem = NULL;
		tmp->m_next = NULL;
		
		if(item->m_bAutoDelete)
		{
			if(m_parent && IsWindowPtr(m_parent->Parent()))
			{
				HWND hWnd = m_parent->Parent()->Handle();
				if(hWnd)
				{
					ds.CtlID = GetIndex();
					ds.CtlType = ODT_LISTBOX;
					ds.hwndItem = m_parent->Handle();
					ds.itemID = index;
					ds.itemData = item->GetData();
					SendMessage(hWnd,WM_DELETEITEM,m_parent->GetId(),(LPARAM)&ds);
				}
			}
			delete item;
			Del(tmp);
		}
		return TRUE;
	}
	return FALSE;
}

int RingOptionItemPack::GetSubItemIndex(LPCTSTR lpszName)
{
	LPRPDATAPACKITEM tmp = m_SubItem;
	int index = -1;
	
	while(tmp && tmp->m_item)
	{
		index ++;
		if(strcmp(tmp->m_item->GetName(),lpszName) == 0)
			return index;
		tmp = tmp->m_next;		
	}
	return index;
}

int RingOptionItemPack::GetSubItemCount()
{
	int cnt = 0;
	LPRPDATAPACKITEM tmp = m_SubItem;
	
	while(tmp && tmp->m_item)
	{
		cnt ++;
		tmp = tmp->m_next;		
	}
	return cnt;
}

RingOptionItem* RingOptionItemPack::GetSubItem(int nIndex)
{
	LPRPDATAPACKITEM tmp = m_SubItem;
	int idx = 0;

	while(tmp && tmp->m_item)
	{
		if(nIndex == idx++)
			return tmp->m_item;

		tmp = tmp->m_next;		
	}
	return NULL;
}

RingOptionItem* RingOptionItemPack::GetSubItem(LPCTSTR lpszName)
{
	LPRPDATAPACKITEM tmp = m_SubItem;
	
	while(tmp && tmp->m_item)
	{
		if(strcmp(tmp->m_item->GetName(),lpszName) == 0)
			return tmp->m_item;
		tmp = tmp->m_next;		
	}
	return NULL;
}